///\file housegl.hh
///\brief contient la définition d'HouseGL, une maison visitable en OpenGL
///\author Allan BLANCHARD
#ifndef _HOUSEGL
#define _HOUSEGL

#include "depmodel.hh"
#include "glapplication.hh"
#include "light.hh"
#include "camera.hpp"

#include <vector>

class HouseGLCreator;

///\class HouseGL
///\brief GLApplication contenant une maison
class HouseGL : public GLApplication{
friend class HouseGLCreator;
private :
  ///\brief Constructeur
  ///construit une maison vide et sans mur, et sans toi(t), et sans sol(e).
  ///\param width largeur de la fenêtre
  ///\param height hauteur de la fenêtre
  ///\param name nom de la fenêtre
  HouseGL(unsigned int width, unsigned int height, const char* name);

private :
  Camera camera;    ///< Camera
  Light<0> lumiere; ///< Lumière basique
  Light<1> soleil;  ///< Essai de lumière solaire
  Light<2> lampe; ///< Essai de lumière lampe orangée
  std::vector<Model*>models; ///< Liste des objets de la pièce
 
  float lastmousex; ///< dernière position de la souris en X
  float lastmousey; ///< derniere position de la souris en Y

  float debout; ///< hauteur relative de la camera
  float eyex;   ///< position de l'oeil en x
  float eyez;   ///< position de l'oeil en z

  float phi;    ///< angle du regard dans le plan x/z
  float psi;    ///< angle du regard dans le plan x/y
  bool repere;  ///< affichage du repère 

  float ecartement; ///< ecartement anaglyphique, si 0 => pas d'anaglyphe

  float xmax; ///< taille max en x des objets
  float xmin; ///< taille min en x des objets
  float ymax; ///< taille max en y des objets
  float ymin; ///< taille min en y des objets
  float zmax; ///< taille max en z des objets
  float zmin; ///< taille min en z des objets
    
public :
  ///\brief
  ///fonction d'affichage
  void display();

  ///\brief
  ///fonction d'idle
  void idle();
  
  ///\brief
  ///fonction de test des touches "normales"
  ///Le mapping est le suivant : 
  ///- z : avancer
  ///- q : se décaler sur la gauche
  ///- s : reculer
  ///- d : se décaler sur la droite
  ///- 0 : activer/désactiver l'affichage du repère
  ///\param key touche
  ///\param x   position souris x
  ///\param y   position souris y
  void keynormal(unsigned char key, int x, int y);

  ///\brief 
  ///fonction touche spéciale : rien de mappé
  ///\param key touche
  ///\param x   position souris x
  ///\param y   position souris y
  void keyspecial(int key, int x, int y);

  ///\brief
  ///test d'évènements bouton de souris
  ///Le mapping est le suivant :
  ///- Molette haut : monter l'oeil sur y
  ///- Molette bas  : descender l'oeil sur y
  ///Limite de hauteur : point le plus bas de la scène -> point le plus haut
  ///\param b bouton de souris
  ///\param e etat du bouton
  ///\param x position souris en x
  ///\param y position souris en y
  void mouseclick(int b, int e, int x, int y);

  ///\brief
  ///Test d'évènements mouvement souris avec souris active
  ///La souris dirige le regard.
  ///La limite au niveau de l'angle du plan xy est 1° -> 179°
  ///\param x position sur x
  ///\param y position sur y
  void mousemot(int x, int y);

  ///\brief
  ///Tests d'évènements mouvement souris avec souris non active
  ///Même mapping que sur mousemot
  ///\param x position sur x
  ///\param y position sur y
  void passivemousemotion(int x, int y);

  ///\brief
  ///nettoie la mémoire
  void exit();

  ///\brief
  ///Ajouter un modèle à la liste des objets de la pièce
  ///\param m modèle à ajouter
  ///\param ignore ignorer les dimensions du modèle
  void addModel(Model  &m, bool ignore = false);
};

///\class HouseGLCreator
///\brief Crée une classe HouseGL
class HouseGLCreator : public GLAppCreator{
  friend class GLApplication;

public :
  ///\brief Constructeur
  ///crée un monteur de HouseGL
  ///\param width : largeur de la fenêtre
  ///\param height : hauteur de la fenêtre
  ///\param name : nom de l'application
  HouseGLCreator(unsigned int width, unsigned int height, const char* name) :
    GLAppCreator(width, height, name) {}
  
  ///\brief
  ///permet de récupérer l'instance en cours de GLApplication castée
  ///(si possible) en HouseGL
  ///\return instance d'HouseGL
  HouseGL* getInstanceOfHouseGL(){
    return static_cast<HouseGL*>(GLApplication::create(*this));
  }

private :
  ///\brief
  ///crée une HouseGL
  ///\return nouvel objet HouseGL
  GLApplication* create(){
    return new HouseGL(w, h, name);
  }
};

#endif
